/*
 * @copyright 2010 Gerald Jacobson
 * @license GNU General Public License
 * 
 * This file is part of Descent Assistant.
 *
 * Descent Assistant is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Descent Assistant is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Descent Assistant.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.amphiprion.descenttool.dao;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.amphiprion.descenttool.Home;
import org.amphiprion.descenttool.entity.AvailableMonster;
import org.amphiprion.descenttool.entity.Monster;
import org.amphiprion.descenttool.entity.Monster.AttackType;
import org.amphiprion.descenttool.entity.Skill;
import org.amphiprion.descenttool.util.ApplicationConstants;
import org.amphiprion.descenttool.util.AvailableMonsterComparator;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import android.os.Environment;
import android.util.Log;

/**
 * @author Amphiprion
 * 
 */
public class MonsterDao extends AbstractDao {
	private static MonsterDao instance;

	public static MonsterDao getInstance() {
		if (instance == null) {
			instance = new MonsterDao();
		}
		return instance;
	}

	public Monster getMonster(String id, String level) {
		Monster result = null;
		String lng = Locale.getDefault().getLanguage();
		try {
			File f = new File(Environment.getExternalStorageDirectory() + "/" + ApplicationConstants.DIRECTORY + "/monsters.xml");

			InputStream is = null;
			if (f.exists()) {
				is = new FileInputStream(f);
			}
			if (is == null) {
				is = Home.class.getResourceAsStream("/monsters.xml");
			}

			DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
			builderFactory.setNamespaceAware(true);

			DocumentBuilder builder = builderFactory.newDocumentBuilder();
			Document document = builder.parse(is);

			NodeList list = document.getElementsByTagName("monster");
			for (int i = 0; i < list.getLength(); i++) {
				Element monsterNode = (Element) list.item(i);
				String curid = monsterNode.getAttributes().getNamedItem("id").getNodeValue();
				if (id.equals(curid)) {
					String extendsId = getAttribute(monsterNode, "extends", null);
					if (extendsId != null) {
						result = getMonster(extendsId, level);
					}
					// ATTACK
					AttackType attackType = null;
					String att = getAttribute(monsterNode, "attack", null);
					if ("melee".equals(att)) {
						attackType = AttackType.MELEE;
					} else if ("range".equals(att)) {
						attackType = AttackType.RANGE;
					} else if ("magic".equals(att)) {
						attackType = AttackType.MAGIC;
					} else if ("morph".equals(att)) {
						attackType = AttackType.MORPH;
					}
					// IMAGE
					String image = getAttribute(monsterNode, "image", null);

					// MAJOR
					String sMajor = getAttribute(monsterNode, "major", null);

					// CLAZZ
					String clazz = getAttribute(monsterNode, "class", null);

					// NAME
					NodeList names = monsterNode.getElementsByTagName("name");
					String name = null;
					if (names.getLength() > 0) {
						Element nameEl = (Element) names.item(0);
						NodeList langs = nameEl.getElementsByTagName("lang");
						for (int iNames = 0; iNames < langs.getLength(); iNames++) {
							Element lang = (Element) langs.item(iNames);
							String local = getAttribute(lang, "id", "");
							if (local.equals(lng)) {
								name = langs.item(iNames).getFirstChild().getNodeValue();
								break;
							} else if ("en".equals(local)) {
								name = langs.item(iNames).getFirstChild().getNodeValue();
							}
						}
					}
					// LEVEL
					NodeList levels = monsterNode.getElementsByTagName("level");
					Element levelNode = null;
					for (int iLevel = 0; iLevel < levels.getLength(); iLevel++) {
						String curlevelid = levels.item(iLevel).getAttributes().getNamedItem("id").getNodeValue();
						if (level.equals(curlevelid)) {
							levelNode = (Element) levels.item(iLevel);
							break;
						}
					}
					if (levelNode == null && result == null) {
						// level not found
						break;
					}

					if (levelNode == null) {
						levelNode = monsterNode;
					}
					Element attNode = (Element) levelNode.getElementsByTagName("attribute").item(0);
					String sMove = getAttribute(attNode, "move", "0");
					String sHealth = getAttribute(attNode, "health", "0");
					String sArmor = getAttribute(attNode, "armor", "0");
					if (result == null) {
						int move = 0;
						if (sMove.startsWith("!")) {
							move = Integer.parseInt(sMove.substring(1));
						} else {
							move = Integer.parseInt(sMove);
						}
						int health = 0;
						if (sHealth.startsWith("!")) {
							health = Integer.parseInt(sHealth.substring(1));
						} else {
							health = Integer.parseInt(sHealth);
						}
						int armor = 0;
						if (sArmor.startsWith("!")) {
							armor = Integer.parseInt(sArmor.substring(1));
						} else {
							armor = Integer.parseInt(sArmor);
						}
						result = new Monster(move, health, armor);
					} else {
						int move = result.getMove();
						if (sMove.startsWith("!")) {
							move = Integer.parseInt(sMove.substring(1));
						} else {
							move += Integer.parseInt(sMove);
						}
						int health = result.getHealth();
						if (sHealth.startsWith("!")) {
							health = Integer.parseInt(sHealth.substring(1));
						} else {
							health += Integer.parseInt(sHealth);
						}
						int armor = result.getArmor();
						if (sArmor.startsWith("!")) {
							armor = Integer.parseInt(sArmor.substring(1));
						} else {
							armor += Integer.parseInt(sArmor);
						}
						result.setMoveStart(move);
						result.setHealthStart(health);
						result.setArmorStart(armor);
					}
					if (name != null) {
						result.name = name;
					}
					if (clazz != null) {
						result.clazz = clazz;
					}
					if (attackType != null) {
						result.attackType = attackType;
					}
					if (sMajor != null) {
						result.major = "true".equals(sMajor);
					}
					if (image != null) {
						result.image = image;
					}
					result.extend = extendsId;
					result.id = curid;
					result.level = level;
					// DICES
					Element diceNode = (Element) levelNode.getElementsByTagName("dice").item(0);
					result.diceBlack += Integer.parseInt(getAttribute(diceNode, "black", "0"));
					result.diceBlue += Integer.parseInt(getAttribute(diceNode, "blue", "0"));
					result.diceGold += Integer.parseInt(getAttribute(diceNode, "gold", "0"));
					result.diceGreen += Integer.parseInt(getAttribute(diceNode, "green", "0"));
					result.diceMorph += Integer.parseInt(getAttribute(diceNode, "morph", "0"));
					result.diceRed += Integer.parseInt(getAttribute(diceNode, "red", "0"));
					result.diceSilver += Integer.parseInt(getAttribute(diceNode, "silver", "0"));
					result.diceWhite += Integer.parseInt(getAttribute(diceNode, "white", "0"));
					result.diceYellow += Integer.parseInt(getAttribute(diceNode, "yellow", "0"));

					// SKILLS
					NodeList listSkill = levelNode.getElementsByTagName("skill");
					for (int iSkill = 0; iSkill < listSkill.getLength(); iSkill++) {
						Element skillNode = (Element) listSkill.item(iSkill);
						String skillId = skillNode.getAttribute("id");
						String mode = getAttribute(skillNode, "mode", "add");
						if ("add".equals(mode)) {
							Skill skill = SkillDao.getInstance().getSkill(skillId);
							skill.setValue(Integer.parseInt(getAttribute(skillNode, "value", "1")));
							result.addSkill(skill);
						} else if ("remove".equals(mode)) {
							result.removeSkill(skillId);
						} else {
							// replace
							result.removeSkill(skillId);

							Skill skill = SkillDao.getInstance().getSkill(skillId);
							skill.setValue(Integer.parseInt(getAttribute(skillNode, "value", "1")));
							result.addSkill(skill);
						}
					}
				}
			}
			is.close();
			return result;
		} catch (Throwable e) {
			Log.e(ApplicationConstants.PACKAGE, "", e);
			return null;
		}
	}

	public List<AvailableMonster> getMonsters(String nameFilter) {
		List<AvailableMonster> result = new ArrayList<AvailableMonster>();
		String lng = Locale.getDefault().getLanguage();
		try {
			File f = new File(Environment.getExternalStorageDirectory() + "/" + ApplicationConstants.DIRECTORY + "/monsters.xml");

			InputStream is = null;
			if (f.exists()) {
				is = new FileInputStream(f);
			}
			if (is == null) {
				is = Home.class.getResourceAsStream("/monsters.xml");
			}

			DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
			builderFactory.setNamespaceAware(true);

			DocumentBuilder builder = builderFactory.newDocumentBuilder();
			Document document = builder.parse(is);

			NodeList list = document.getElementsByTagName("monster");
			for (int i = 0; i < list.getLength(); i++) {
				Element monsterNode = (Element) list.item(i);
				String id = monsterNode.getAttributes().getNamedItem("id").getNodeValue();
				String extend = getAttribute(monsterNode, "extends", null);
				String clazz = null;
				if (extend == null) {
					clazz = getAttribute(monsterNode, "class", null);
				} else {
					for (AvailableMonster m : result) {
						if (m.id.equals(extend)) {
							clazz = m.clazz;
							break;
						}
					}
				}
				NodeList names = monsterNode.getElementsByTagName("name");
				String name = "";
				if (names.getLength() > 0) {
					Element nameEl = (Element) names.item(0);
					NodeList langs = nameEl.getElementsByTagName("lang");
					for (int iNames = 0; iNames < langs.getLength(); iNames++) {
						Element lang = (Element) langs.item(iNames);
						String local = getAttribute(lang, "id", "");
						if (local.equals(lng)) {
							name = langs.item(iNames).getFirstChild().getNodeValue();
							break;
						} else if ("en".equals(local)) {
							name = langs.item(iNames).getFirstChild().getNodeValue();
						}
					}
				}
				if (name.toUpperCase().contains(nameFilter.toUpperCase())) {
					AvailableMonster am = new AvailableMonster();
					am.id = id;
					am.name = name;
					am.clazz = clazz;
					am.extend = extend;

					result.add(am);
				}
			}
			is.close();
		} catch (Throwable e) {
			Log.e("org.amphiprion.descenttool", "", e);
		}
		Collections.sort(result, new AvailableMonsterComparator());
		return result;
	}
}
